<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>node_modules/egg-core/lib/loader/mixin/plugin.js - Documentation</title>

    <script src="scripts/prettify/prettify.js"></script>
    <script src="scripts/prettify/lang-css.js"></script>
    <!--[if lt IE 9]>
      <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
    <![endif]-->
    <link type="text/css" rel="stylesheet" href="styles/ionicons.min.css">
    <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
    <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>

<input type="checkbox" id="nav-trigger" class="nav-trigger" />
<label for="nav-trigger" class="navicon-button x">
  <div class="navicon"></div>
</label>

<label for="nav-trigger" class="overlay"></label>

<nav>
    <h2><a href="index.html">Home</a></h2>
  <h3>Egg</h3>
  <ul>
    <li>
      <a href="Egg.html">Egg</a>
      <a href="Application.html">Application</a>
      <a href="Context.html">Context</a>
      <a href="Request.html">Request</a>
      <a href="Response.html">Response</a>
    </li>
  </ul>
  <h3>Classes</h3><ul><li><a href="Agent.html">Agent</a><ul class='members'><li data-type='member'><a href="Agent.html#coreLogger">coreLogger</a></li><li data-type='member'><a href="Agent.html#env">env</a></li><li data-type='member'><a href="Agent.html#httpclient">httpclient</a></li><li data-type='member'><a href="Agent.html#logger">logger</a></li><li data-type='member'><a href="Agent.html#loggers">loggers</a></li><li data-type='member'><a href="Agent.html#messenger">messenger</a></li><li data-type='member'><a href="Agent.html#proxy">proxy</a></li><li data-type='member'><a href="Agent.html#addSingleton">addSingleton()</a></li><li data-type='member'><a href="Agent.html#cluster">cluster()</a></li><li data-type='member'><a href="Agent.html#curl">curl()</a></li><li data-type='member'><a href="Agent.html#getLogger">getLogger()</a></li><li data-type='member'><a href="Agent.html#inspect">inspect()</a></li></ul></li><li><a href="AgentWorkerLoader.html">AgentWorkerLoader</a><ul class='members'><li data-type='member'><a href="AgentWorkerLoader.html#loadConfig">loadConfig()</a></li></ul></li><li><a href="AppInfo.html">AppInfo</a><ul class='members'><li data-type='member'><a href="AppInfo.html#baseDir">baseDir</a></li><li data-type='member'><a href="AppInfo.html#env">env</a></li><li data-type='member'><a href="AppInfo.html#HOME">HOME</a></li><li data-type='member'><a href="AppInfo.html#name">name</a></li><li data-type='member'><a href="AppInfo.html#pkg">pkg</a></li><li data-type='member'><a href="AppInfo.html#root">root</a></li><li data-type='member'><a href="AppInfo.html#scope">scope</a></li></ul></li><li><a href="Application.html">Application</a><ul class='members'><li data-type='member'><a href="Application.html#coreLogger">coreLogger</a></li><li data-type='member'><a href="Application.html#createAnonymousContext">createAnonymousContext</a></li><li data-type='member'><a href="Application.html#env">env</a></li><li data-type='member'><a href="Application.html#Helper">Helper</a></li><li data-type='member'><a href="Application.html#httpclient">httpclient</a></li><li data-type='member'><a href="Application.html#keys">keys</a></li><li data-type='member'><a href="Application.html#locals">locals</a></li><li data-type='member'><a href="Application.html#logger">logger</a></li><li data-type='member'><a href="Application.html#loggers">loggers</a></li><li data-type='member'><a href="Application.html#messenger">messenger</a></li><li data-type='member'><a href="Application.html#proxy">proxy</a></li><li data-type='member'><a href="Application.html#view">view</a></li><li data-type='member'><a href="Application.html#addSingleton">addSingleton()</a></li><li data-type='member'><a href="Application.html#cluster">cluster()</a></li><li data-type='member'><a href="Application.html#createContext">createContext()</a></li><li data-type='member'><a href="Application.html#curl">curl()</a></li><li data-type='member'><a href="Application.html#getLogger">getLogger()</a></li><li data-type='member'><a href="Application.html#inspect">inspect()</a></li><li data-type='member'><a href="Application.html#runInBackground">runInBackground()</a></li></ul></li><li><a href="AppWorkerLoader.html">AppWorkerLoader</a><ul class='members'><li data-type='member'><a href="AppWorkerLoader.html#load">load()</a></li><li data-type='member'><a href="AppWorkerLoader.html#loadConfig">loadConfig()</a></li></ul></li><li><a href="global.html#BaseContextClass">BaseContextClass</a><ul class='members'><li data-type='member'><a href="global.html#BaseContextClass#app">app</a></li><li data-type='member'><a href="global.html#BaseContextClass#config">config</a></li><li data-type='member'><a href="global.html#BaseContextClass#ctx">ctx</a></li><li data-type='member'><a href="global.html#BaseContextClass#service">service</a></li></ul></li><li><a href="BaseContextLogger.html">BaseContextLogger</a><ul class='members'><li data-type='member'><a href="BaseContextLogger.html#ctx">ctx</a></li><li data-type='member'><a href="BaseContextLogger.html#debug">debug</a></li><li data-type='member'><a href="BaseContextLogger.html#error">error</a></li><li data-type='member'><a href="BaseContextLogger.html#info">info</a></li><li data-type='member'><a href="BaseContextLogger.html#warn">warn</a></li></ul></li><li><a href="Config.html">Config</a><ul class='members'><li data-type='member'><a href="Config.html#baseDir">baseDir</a></li><li data-type='member'><a href="Config.html#bodyParser">bodyParser</a></li><li data-type='member'><a href="Config.html#cluster">cluster</a></li><li data-type='member'><a href="Config.html#confusedConfigurations">confusedConfigurations</a></li><li data-type='member'><a href="Config.html#development">development</a></li><li data-type='member'><a href="Config.html#dump">dump</a></li><li data-type='member'><a href="Config.html#env">env</a></li><li data-type='member'><a href="Config.html#HOME">HOME</a></li><li data-type='member'><a href="Config.html#hostHeaders">hostHeaders</a></li><li data-type='member'><a href="Config.html#httpclient">httpclient</a></li><li data-type='member'><a href="Config.html#i18n">i18n</a></li><li data-type='member'><a href="Config.html#ipHeaders">ipHeaders</a></li><li data-type='member'><a href="Config.html#jsonp">jsonp</a></li><li data-type='member'><a href="Config.html#keys">keys</a></li><li data-type='member'><a href="Config.html#logger">logger</a></li><li data-type='member'><a href="Config.html#logrotator">logrotator</a></li><li data-type='member'><a href="Config.html#meta">meta</a></li><li data-type='member'><a href="Config.html#middleware">middleware</a></li><li data-type='member'><a href="Config.html#multipart">multipart</a></li><li data-type='member'><a href="Config.html#name">name</a></li><li data-type='member'><a href="Config.html#notfound">notfound</a></li><li data-type='member'><a href="Config.html#onClientError">onClientError</a></li><li data-type='member'><a href="Config.html#pkg">pkg</a></li><li data-type='member'><a href="Config.html#protocolHeaders">protocolHeaders</a></li><li data-type='member'><a href="Config.html#proxy">proxy</a></li><li data-type='member'><a href="Config.html#rundir">rundir</a></li><li data-type='member'><a href="Config.html#security">security</a></li><li data-type='member'><a href="Config.html#siteFile">siteFile</a></li><li data-type='member'><a href="Config.html#static">static</a></li><li data-type='member'><a href="Config.html#view">view</a></li><li data-type='member'><a href="Config.html#watcher">watcher</a></li><li data-type='member'><a href="Config.html#.workerStartTimeout">workerStartTimeout</a></li></ul></li><li><a href="Context.html">Context</a><ul class='members'><li data-type='member'><a href="Context.html#accept">accept</a></li><li data-type='member'><a href="Context.html#acceptJSON">acceptJSON</a></li><li data-type='member'><a href="Context.html#coreLogger">coreLogger</a></li><li data-type='member'><a href="Context.html#helper">helper</a></li><li data-type='member'><a href="Context.html#ip">ip</a></li><li data-type='member'><a href="Context.html#locale">locale</a></li><li data-type='member'><a href="Context.html#locals">locals</a></li><li data-type='member'><a href="Context.html#logger">logger</a></li><li data-type='member'><a href="Context.html#params">params</a></li><li data-type='member'><a href="Context.html#queries">queries</a></li><li data-type='member'><a href="Context.html#realStatus">realStatus</a></li><li data-type='member'><a href="Context.html#router">router</a></li><li data-type='member'><a href="Context.html#starttime">starttime</a></li><li data-type='member'><a href="Context.html#view">view</a></li><li data-type='member'><a href="Context.html#__">__()</a></li><li data-type='member'><a href="Context.html#curl">curl()</a></li><li data-type='member'><a href="Context.html#getFileStream">getFileStream()</a></li><li data-type='member'><a href="Context.html#gettext">gettext()</a></li><li data-type='member'><a href="Context.html#multipart">multipart()</a></li><li data-type='member'><a href="Context.html#redirect">redirect()</a></li></ul></li><li><a href="ContextLoader.html">ContextLoader</a><ul class='members'><li data-type='member'><a href="ContextLoader.html#load">load()</a></li><li data-type='member'><a href="ContextLoader.html#parse">parse()</a></li></ul></li><li><a href="global.html#Controller">Controller</a><ul class='members'><li data-type='member'><a href="global.html#Controller#app">app</a></li><li data-type='member'><a href="global.html#Controller#config">config</a></li><li data-type='member'><a href="global.html#Controller#ctx">ctx</a></li><li data-type='member'><a href="global.html#Controller#service">service</a></li></ul></li><li><a href="EggApplication.html">EggApplication</a><ul class='members'><li data-type='member'><a href="EggApplication.html#BaseContextClass">BaseContextClass</a></li><li data-type='member'><a href="EggApplication.html#baseDir">baseDir</a></li><li data-type='member'><a href="EggApplication.html#config">config</a></li><li data-type='member'><a href="EggApplication.html#Controller">Controller</a></li><li data-type='member'><a href="EggApplication.html#coreLogger">coreLogger</a></li><li data-type='member'><a href="EggApplication.html#deprecate">deprecate</a></li><li data-type='member'><a href="EggApplication.html#env">env</a></li><li data-type='member'><a href="EggApplication.html#httpclient">httpclient</a></li><li data-type='member'><a href="EggApplication.html#loader">loader</a></li><li data-type='member'><a href="EggApplication.html#logger">logger</a></li><li data-type='member'><a href="EggApplication.html#loggers">loggers</a></li><li data-type='member'><a href="EggApplication.html#messenger">messenger</a></li><li data-type='member'><a href="EggApplication.html#name">name</a></li><li data-type='member'><a href="EggApplication.html#plugins">plugins</a></li><li data-type='member'><a href="EggApplication.html#proxy">proxy</a></li><li data-type='member'><a href="EggApplication.html#router">router</a></li><li data-type='member'><a href="EggApplication.html#Service">Service</a></li><li data-type='member'><a href="EggApplication.html#type">type</a></li><li data-type='member'><a href="EggApplication.html#addSingleton">addSingleton()</a></li><li data-type='member'><a href="EggApplication.html#beforeClose">beforeClose()</a></li><li data-type='member'><a href="EggApplication.html#beforeStart">beforeStart()</a></li><li data-type='member'><a href="EggApplication.html#close">close()</a></li><li data-type='member'><a href="EggApplication.html#cluster">cluster()</a></li><li data-type='member'><a href="EggApplication.html#curl">curl()</a></li><li data-type='member'><a href="EggApplication.html#getLogger">getLogger()</a></li><li data-type='member'><a href="EggApplication.html#inspect">inspect()</a></li><li data-type='member'><a href="EggApplication.html#toAsyncFunction">toAsyncFunction()</a></li><li data-type='member'><a href="EggApplication.html#toPromise">toPromise()</a></li><li data-type='member'><a href="EggApplication.html#url">url()</a></li><li data-type='member'><a href="EggApplication.html#use">use()</a></li></ul></li><li><a href="EggCore.html">EggCore</a><ul class='members'><li data-type='member'><a href="EggCore.html#BaseContextClass">BaseContextClass</a></li><li data-type='member'><a href="EggCore.html#baseDir">baseDir</a></li><li data-type='member'><a href="EggCore.html#config">config</a></li><li data-type='member'><a href="EggCore.html#Controller">Controller</a></li><li data-type='member'><a href="EggCore.html#deprecate">deprecate</a></li><li data-type='member'><a href="EggCore.html#loader">loader</a></li><li data-type='member'><a href="EggCore.html#name">name</a></li><li data-type='member'><a href="EggCore.html#plugins">plugins</a></li><li data-type='member'><a href="EggCore.html#router">router</a></li><li data-type='member'><a href="EggCore.html#Service">Service</a></li><li data-type='member'><a href="EggCore.html#type">type</a></li><li data-type='member'><a href="EggCore.html#beforeClose">beforeClose()</a></li><li data-type='member'><a href="EggCore.html#beforeStart">beforeStart()</a></li><li data-type='member'><a href="EggCore.html#close">close()</a></li><li data-type='member'><a href="EggCore.html#toAsyncFunction">toAsyncFunction()</a></li><li data-type='member'><a href="EggCore.html#toPromise">toPromise()</a></li><li data-type='member'><a href="EggCore.html#url">url()</a></li><li data-type='member'><a href="EggCore.html#use">use()</a></li></ul></li><li><a href="EggLoader.html">EggLoader</a><ul class='members'><li data-type='member'><a href="EggLoader.html#appInfo">appInfo</a></li><li data-type='member'><a href="EggLoader.html#ContextLoader">ContextLoader</a></li><li data-type='member'><a href="EggLoader.html#eggPaths">eggPaths</a></li><li data-type='member'><a href="EggLoader.html#FileLoader">FileLoader</a></li><li data-type='member'><a href="EggLoader.html#pkg">pkg</a></li><li data-type='member'><a href="EggLoader.html#plugins">plugins</a></li><li data-type='member'><a href="EggLoader.html#serverEnv">serverEnv</a></li><li data-type='member'><a href="EggLoader.html#serverScope">serverScope</a></li><li data-type='member'><a href="EggLoader.html#getAppInfo">getAppInfo()</a></li><li data-type='member'><a href="EggLoader.html#getHomedir">getHomedir()</a></li><li data-type='member'><a href="EggLoader.html#getLoadUnits">getLoadUnits()</a></li><li data-type='member'><a href="EggLoader.html#loadAgentExtend">loadAgentExtend()</a></li><li data-type='member'><a href="EggLoader.html#loadApplicationExtend">loadApplicationExtend()</a></li><li data-type='member'><a href="EggLoader.html#loadConfig">loadConfig()</a></li><li data-type='member'><a href="EggLoader.html#loadContextExtend">loadContextExtend()</a></li><li data-type='member'><a href="EggLoader.html#loadFile">loadFile()</a></li><li data-type='member'><a href="EggLoader.html#loadHelperExtend">loadHelperExtend()</a></li><li data-type='member'><a href="EggLoader.html#loadMiddleware">loadMiddleware()</a></li><li data-type='member'><a href="EggLoader.html#loadPlugin">loadPlugin()</a></li><li data-type='member'><a href="EggLoader.html#loadRequestExtend">loadRequestExtend()</a></li><li data-type='member'><a href="EggLoader.html#loadResponseExtend">loadResponseExtend()</a></li><li data-type='member'><a href="EggLoader.html#loadRouter">loadRouter()</a></li><li data-type='member'><a href="EggLoader.html#loadService">loadService()</a></li><li data-type='member'><a href="EggLoader.html#loadToApp">loadToApp()</a></li><li data-type='member'><a href="EggLoader.html#loadToContext">loadToContext()</a></li></ul></li><li><a href="FileLoader.html">FileLoader</a><ul class='members'><li data-type='member'><a href="FileLoader.html#load">load()</a></li><li data-type='member'><a href="FileLoader.html#parse">parse()</a></li></ul></li><li><a href="Helper.html">Helper</a><ul class='members'><li data-type='member'><a href="Helper.html#pathFor">pathFor()</a></li><li data-type='member'><a href="Helper.html#urlFor">urlFor()</a></li></ul></li><li><a href="I18n.html">I18n</a></li><li><a href="Messenger.html">Messenger</a><ul class='members'><li data-type='member'><a href="Messenger.html#broadcast">broadcast()</a></li><li data-type='member'><a href="Messenger.html#send">send()</a></li><li data-type='member'><a href="Messenger.html#sendRandom">sendRandom()</a></li><li data-type='member'><a href="Messenger.html#sendTo">sendTo()</a></li><li data-type='member'><a href="Messenger.html#sendToAgent">sendToAgent()</a></li><li data-type='member'><a href="Messenger.html#sendToApp">sendToApp()</a></li></ul></li><li><a href="Request.html">Request</a><ul class='members'><li data-type='member'><a href="Request.html#acceptJSON">acceptJSON</a></li><li data-type='member'><a href="Request.html#header">header</a></li><li data-type='member'><a href="Request.html#headers">headers</a></li><li data-type='member'><a href="Request.html#host">host</a></li><li data-type='member'><a href="Request.html#ip">ip</a></li><li data-type='member'><a href="Request.html#ips">ips</a></li><li data-type='member'><a href="Request.html#method">method</a></li><li data-type='member'><a href="Request.html#originalUrl">originalUrl</a></li><li data-type='member'><a href="Request.html#path">path</a></li><li data-type='member'><a href="Request.html#protocol">protocol</a></li><li data-type='member'><a href="Request.html#queries">queries</a></li><li data-type='member'><a href="Request.html#query">query</a></li><li data-type='member'><a href="Request.html#querystring">querystring</a></li><li data-type='member'><a href="Request.html#url">url</a></li><li data-type='member'><a href="Request.html#query">query()</a></li></ul></li><li><a href="Response.html">Response</a><ul class='members'><li data-type='member'><a href="Response.html#realStatus">realStatus</a></li><li data-type='member'><a href="Response.html#type">type</a></li><li data-type='member'><a href="Response.html#type">type</a></li></ul></li><li><a href="Router.html">Router</a><ul class='members'><li data-type='member'><a href="Router.html#register">register()</a></li><li data-type='member'><a href="Router.html#resources">resources()</a></li><li data-type='member'><a href="Router.html#url">url()</a></li></ul></li><li><a href="global.html#Service">Service</a><ul class='members'><li data-type='member'><a href="global.html#Service#app">app</a></li><li data-type='member'><a href="global.html#Service#config">config</a></li><li data-type='member'><a href="global.html#Service#ctx">ctx</a></li><li data-type='member'><a href="global.html#Service#service">service</a></li></ul></li></ul><h3>Namespaces</h3><ul><li><a href="Egg.html">Egg</a><ul class='members'><li data-type='member'><a href="Egg.html#Agent">Agent</a></li><li data-type='member'><a href="Egg.html#AgentWorkerLoader">AgentWorkerLoader</a></li><li data-type='member'><a href="Egg.html#Application">Application</a></li><li data-type='member'><a href="Egg.html#AppWorkerLoader">AppWorkerLoader</a></li><li data-type='member'><a href="Egg.html#BaseContextClass">BaseContextClass</a></li><li data-type='member'><a href="Egg.html#Controller">Controller</a></li><li data-type='member'><a href="Egg.html#Service">Service</a></li><li data-type='member'><a href="Egg.html#Subscription">Subscription</a></li></ul></li></ul>
</nav>

<div id="main">
    
    <h1 class="page-title">node_modules/egg-core/lib/loader/mixin/plugin.js</h1>
    

    



    
    <section>
        <article>
            <pre class="prettyprint source linenums"><code>'use strict';

const fs = require('fs');
const path = require('path');
const debug = require('debug')('egg-core:plugin');
const sequencify = require('../../utils/sequencify');
const loadFile = require('../../utils').loadFile;


module.exports = {

  /**
   * Load config/plugin.js from {EggLoader#loadUnits}
   *
   * plugin.js is written below
   *
   * ```js
   * {
   *   'xxx-client': {
   *     enable: true,
   *     package: 'xxx-client',
   *     dep: [],
   *     env: [],
   *   },
   *   // short hand
   *   'rds': false,
   *   'depd': {
   *     enable: true,
   *     path: 'path/to/depd'
   *   }
   * }
   * ```
   *
   * If the plugin has path, Loader will find the module from it.
   *
   * Otherwise Loader will lookup follow the order by packageName
   *
   * 1. $APP_BASE/node_modules/${package}
   * 2. $EGG_BASE/node_modules/${package}
   *
   * You can call `loader.plugins` that retrieve enabled plugins.
   *
   * ```js
   * loader.plugins['xxx-client'] = {
   *   name: 'xxx-client',                 // the plugin name, it can be used in `dep`
   *   package: 'xxx-client',              // the package name of plugin
   *   enable: true,                       // whether enabled
   *   path: 'path/to/xxx-client',         // the directory of the plugin package
   *   dep: [],                            // the dependent plugins, you can use the plugin name
   *   env: [ 'local', 'unittest' ],       // specify the serverEnv that only enable the plugin in it
   * }
   * ```
   *
   * `loader.allPlugins` can be used when retrieve all plugins.
   * @method EggLoader#loadPlugin
   * @since 1.0.0
   */
  loadPlugin() {
    this.timing.start('Load Plugin');

    // loader plugins from application
    const appPlugins = this.readPluginConfigs(path.join(this.options.baseDir, 'config/plugin.default'));
    debug('Loaded app plugins: %j', Object.keys(appPlugins));

    // loader plugins from framework
    const eggPluginConfigPaths = this.eggPaths.map(eggPath => path.join(eggPath, 'config/plugin.default'));
    const eggPlugins = this.readPluginConfigs(eggPluginConfigPaths);
    debug('Loaded egg plugins: %j', Object.keys(eggPlugins));

    // loader plugins from process.env.EGG_PLUGINS
    let customPlugins;
    if (process.env.EGG_PLUGINS) {
      try {
        customPlugins = JSON.parse(process.env.EGG_PLUGINS);
      } catch (e) {
        debug('parse EGG_PLUGINS failed, %s', e);
      }
    }

    // loader plugins from options.plugins
    if (this.options.plugins) {
      customPlugins = Object.assign({}, customPlugins, this.options.plugins);
    }

    if (customPlugins) {
      for (const name in customPlugins) {
        this.normalizePluginConfig(customPlugins, name);
      }
      debug('Loaded custom plugins: %j', Object.keys(customPlugins));
    }

    this.allPlugins = {};
    this.appPlugins = appPlugins;
    this.customPlugins = customPlugins;
    this.eggPlugins = eggPlugins;

    this._extendPlugins(this.allPlugins, eggPlugins);
    this._extendPlugins(this.allPlugins, appPlugins);
    this._extendPlugins(this.allPlugins, customPlugins);

    const enabledPluginNames = []; // enabled plugins that configured explicitly
    const plugins = {};
    const env = this.serverEnv;
    for (const name in this.allPlugins) {
      const plugin = this.allPlugins[name];

      // resolve the real plugin.path based on plugin or package
      plugin.path = this.getPluginPath(plugin, this.options.baseDir);

      // read plugin information from ${plugin.path}/package.json
      this.mergePluginConfig(plugin);

      // disable the plugin that not match the serverEnv
      if (env &amp;&amp; plugin.env.length &amp;&amp; !plugin.env.includes(env)) {
        this.options.logger.info('Plugin %s is disabled by env unmatched, require env(%s) but got env is %s', name, plugin.env, env);
        plugin.enable = false;
        continue;
      }

      plugins[name] = plugin;
      if (plugin.enable) {
        enabledPluginNames.push(name);
      }
    }

    // retrieve the ordered plugins
    this.orderPlugins = this.getOrderPlugins(plugins, enabledPluginNames, appPlugins);

    const enablePlugins = {};
    for (const plugin of this.orderPlugins) {
      enablePlugins[plugin.name] = plugin;
    }
    debug('Loaded plugins: %j', Object.keys(enablePlugins));

    /**
     * Retrieve enabled plugins
     * @member {Object} EggLoader#plugins
     * @since 1.0.0
     */
    this.plugins = enablePlugins;

    this.timing.end('Load Plugin');
  },

  /*
   * Read plugin.js from multiple directory
   */
  readPluginConfigs(configPaths) {
    if (!Array.isArray(configPaths)) {
      configPaths = [ configPaths ];
    }

    // Get all plugin configurations
    // plugin.default.js
    // plugin.${scope}.js
    // plugin.${env}.js
    // plugin.${scope}_${env}.js
    const newConfigPaths = [];
    for (const filename of this.getTypeFiles('plugin')) {
      for (let configPath of configPaths) {
        configPath = path.join(path.dirname(configPath), filename);
        newConfigPaths.push(configPath);
      }
    }

    const plugins = {};
    for (const configPath of newConfigPaths) {
      let filepath = this.resolveModule(configPath);

      // let plugin.js compatible
      if (configPath.endsWith('plugin.default') &amp;&amp; !filepath) {
        filepath = this.resolveModule(configPath.replace(/plugin\.default$/, 'plugin'));
      }

      if (!filepath) {
        continue;
      }

      const config = loadFile(filepath);

      for (const name in config) {
        this.normalizePluginConfig(config, name, filepath);
      }

      this._extendPlugins(plugins, config);
    }

    return plugins;
  },

  normalizePluginConfig(plugins, name, configPath) {
    const plugin = plugins[name];

    // plugin_name: false
    if (typeof plugin === 'boolean') {
      plugins[name] = {
        name,
        enable: plugin,
        dependencies: [],
        optionalDependencies: [],
        env: [],
        from: configPath,
      };
      return;
    }

    if (!('enable' in plugin)) {
      plugin.enable = true;
    }
    plugin.name = name;
    plugin.dependencies = plugin.dependencies || [];
    plugin.optionalDependencies = plugin.optionalDependencies || [];
    plugin.env = plugin.env || [];
    plugin.from = configPath;
    depCompatible(plugin);
  },

  // Read plugin information from package.json and merge
  // {
  //   eggPlugin: {
  //     "name": "",    plugin name, must be same as name in config/plugin.js
  //     "dep": [],     dependent plugins
  //     "env": ""      env
  //   }
  // }
  mergePluginConfig(plugin) {
    let pkg;
    let config;
    const pluginPackage = path.join(plugin.path, 'package.json');
    if (fs.existsSync(pluginPackage)) {
      pkg = require(pluginPackage);
      config = pkg.eggPlugin;
      if (pkg.version) {
        plugin.version = pkg.version;
      }
    }

    const logger = this.options.logger;
    if (!config) {
      logger.warn(`[egg:loader] pkg.eggPlugin is missing in ${pluginPackage}`);
      return;
    }

    if (config.name &amp;&amp; config.name !== plugin.name) {
      // pluginName is configured in config/plugin.js
      // pluginConfigName is pkg.eggPath.name
      logger.warn(`[egg:loader] pluginName(${plugin.name}) is different from pluginConfigName(${config.name})`);
    }

    // dep compatible
    depCompatible(config);

    for (const key of [ 'dependencies', 'optionalDependencies', 'env' ]) {
      if (!plugin[key].length &amp;&amp; Array.isArray(config[key])) {
        plugin[key] = config[key];
      }
    }
  },

  getOrderPlugins(allPlugins, enabledPluginNames, appPlugins) {
    // no plugins enabled
    if (!enabledPluginNames.length) {
      return [];
    }

    const result = sequencify(allPlugins, enabledPluginNames);
    debug('Got plugins %j after sequencify', result);

    // catch error when result.sequence is empty
    if (!result.sequence.length) {
      const err = new Error(`sequencify plugins has problem, missing: [${result.missingTasks}], recursive: [${result.recursiveDependencies}]`);
      // find plugins which is required by the missing plugin
      for (const missName of result.missingTasks) {
        const requires = [];
        for (const name in allPlugins) {
          if (allPlugins[name].dependencies.includes(missName)) {
            requires.push(name);
          }
        }
        err.message += `\n\t>> Plugin [${missName}] is disabled or missed, but is required by [${requires}]`;
      }

      err.name = 'PluginSequencifyError';
      throw err;
    }

    // log the plugins that be enabled implicitly
    const implicitEnabledPlugins = [];
    const requireMap = {};
    result.sequence.forEach(name => {
      for (const depName of allPlugins[name].dependencies) {
        if (!requireMap[depName]) {
          requireMap[depName] = [];
        }
        requireMap[depName].push(name);
      }

      if (!allPlugins[name].enable) {
        implicitEnabledPlugins.push(name);
        allPlugins[name].enable = true;
      }
    });

    // Following plugins will be enabled implicitly.
    //   - configclient required by [hsfclient]
    //   - eagleeye required by [hsfclient]
    //   - diamond required by [hsfclient]
    if (implicitEnabledPlugins.length) {
      let message = implicitEnabledPlugins
        .map(name => `  - ${name} required by [${requireMap[name]}]`)
        .join('\n');
      this.options.logger.info(`Following plugins will be enabled implicitly.\n${message}`);

      // should warn when the plugin is disabled by app
      message = implicitEnabledPlugins
        .filter(name => appPlugins[name] &amp;&amp; appPlugins[name].enable === false)
        .map(name => `  - ${name} required by [${requireMap[name]}]`)
        .join('\n');
      this.options.logger.warn(`Following plugins will be enabled implicitly that is disabled by application.\n${message}`);
    }

    return result.sequence.map(name => allPlugins[name]);
  },

  // Get the real plugin path
  getPluginPath(plugin) {
    if (plugin.path) {
      return plugin.path;
    }

    const name = plugin.package || plugin.name;
    const lookupDirs = [];

    // 尝试在以下目录找到匹配的插件
    //  -> {APP_PATH}/node_modules
    //    -> {EGG_PATH}/node_modules
    //      -> $CWD/node_modules
    lookupDirs.push(path.join(this.options.baseDir, 'node_modules'));

    // 到 egg 中查找，优先从外往里查找
    for (let i = this.eggPaths.length - 1; i >= 0; i--) {
      const eggPath = this.eggPaths[i];
      lookupDirs.push(path.join(eggPath, 'node_modules'));
    }

    // should find the $cwd/node_modules when test the plugins under npm3
    lookupDirs.push(path.join(process.cwd(), 'node_modules'));

    for (let dir of lookupDirs) {
      dir = path.join(dir, name);
      if (fs.existsSync(dir)) {
        return fs.realpathSync(dir);
      }
    }

    throw new Error(`Can not find plugin ${name} in "${lookupDirs.join(', ')}"`);
  },

  _extendPlugins(target, plugins) {
    if (!plugins) {
      return;
    }
    for (const name in plugins) {
      const plugin = plugins[name];
      let targetPlugin = target[name];
      if (!targetPlugin) {
        targetPlugin = target[name] = {};
      }
      if (targetPlugin.package &amp;&amp; targetPlugin.package === plugin.package) {
        this.options.logger.warn('plugin %s has been defined that is %j, but you define again in %s',
          name, targetPlugin, plugin.from);
      }
      if (plugin.path || plugin.package) {
        delete targetPlugin.path;
        delete targetPlugin.package;
      }
      for (const prop in plugin) {
        if (plugin[prop] === undefined) {
          continue;
        }
        if (targetPlugin[prop] &amp;&amp; Array.isArray(plugin[prop]) &amp;&amp; !plugin[prop].length) {
          continue;
        }
        targetPlugin[prop] = plugin[prop];
      }
    }
  },

};

function depCompatible(plugin) {
  if (plugin.dep &amp;&amp; !(Array.isArray(plugin.dependencies) &amp;&amp; plugin.dependencies.length)) {
    plugin.dependencies = plugin.dep;
    delete plugin.dep;
  }
}
</code></pre>
        </article>
    </section>




</div>

<br class="clear">

<footer>
    Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Jun 07 2018 08:57:05 GMT+0000 (UTC) using the Minami theme.
</footer>

<script>prettyPrint();</script>
<script src="scripts/linenumber.js"></script>
</body>
</html>
